#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "BooleanStatement.h"
#include "include.h"

BooleanStatement::BooleanStatement(char * operation, BooleanStatement * bs1, BooleanStatement * bs2)
{
	printf("Making BS 1\n");
	strcpy(this->operation, operation);
	this->bs1 = bs1;
	this->bs2 = bs2;
	
	this->tv1 = NULL;
	this->tv2 = NULL;
	
	this->de1 = NULL;
	this->de2 = NULL;
}
BooleanStatement::BooleanStatement(char * operation, BooleanStatement * bs1, TypedValue * tv2)
{
	printf("Making BS 2\n");
	strcpy(this->operation, operation);
	this->bs1 = bs1;
	this->bs2 = NULL;
	
	this->tv1 = NULL;
	this->tv2 = tv2;
	
	this->de1 = NULL;
	this->de2 = NULL;
}
BooleanStatement::BooleanStatement(char * operation, BooleanStatement * bs1, char * de2)
{
	printf("Making BS 3\n");
	strcpy(this->operation, operation);
	this->bs1 = bs1;
	this->bs2 = NULL;
	
	this->tv1 = NULL;
	this->tv2 = NULL;
	
	this->de1 = NULL;
	this->de2 = de2;
}
	
BooleanStatement::BooleanStatement(char * operation, TypedValue * tv1, BooleanStatement * bs2)
{
	printf("Making BS 4\n");
	strcpy(this->operation, operation);
	this->bs1 = NULL;
	this->bs2 = bs2;
	
	this->tv1 = tv1;
	this->tv2 = NULL;
	
	this->de1 = NULL;
	this->de2 = NULL;
}
BooleanStatement::BooleanStatement(char * operation, TypedValue * tv1, TypedValue * tv2)
{
	printf("Making BS 5\n");
	strcpy(this->operation, operation);
	this->bs1 = NULL;
	this->bs2 = NULL;
	
	this->tv1 = tv1;
	this->tv2 = tv2;
	
	this->de1 = NULL;
	this->de2 = NULL;
}
BooleanStatement::BooleanStatement(char * operation, TypedValue * tv1, char * de2)
{
	printf("Making BS 6\n");
	strcpy(this->operation, operation);
	this->bs1 = NULL;
	this->bs2 = NULL;
	
	this->tv1 = tv1;
	this->tv2 = NULL;
	
	this->de1 = NULL;
	this->de2 = de2;
}
	
BooleanStatement::BooleanStatement(char * operation, char * de1, BooleanStatement * bs2)
{
	printf("Making BS 7: de1 = %s\n", de1);
	strcpy(this->operation, operation);
	this->bs1 = NULL;
	this->bs2 = bs2;
	
	this->tv1 = NULL;
	this->tv2 = NULL;
	
	this->de1 = de1;
	this->de2 = NULL;
}
BooleanStatement::BooleanStatement(char * operation, char * de1, TypedValue * tv2)
{
	printf("Making BS 8: de1 = %s\n", de1);
	strcpy(this->operation, operation);
	this->bs1 = NULL;
	this->bs2 = NULL;
	
	this->tv1 = NULL;
	this->tv2 = tv2;
	
	this->de1 = de1;
	this->de2 = NULL;
}
BooleanStatement::BooleanStatement(char * operation, char * de1, char * de2)
{
	printf("Making BS 9: de1 = %s\n", de1);
	strcpy(this->operation, operation);
	this->bs1 = NULL;
	this->bs2 = NULL;
	
	this->tv1 = NULL;
	this->tv2 = NULL;
	
	this->de1 = de1;
	this->de2 = de2;
}
	
BooleanStatement::~BooleanStatement()
{
	if(bs1)
	{
		delete(bs1);
	}
	
	if(bs2)
	{
		delete(bs2);
		bs2 = NULL;
	}
	if(tv1)
	{
		delete(tv1);
		tv1 = NULL;
	}
	if(tv2)
	{
		delete(tv2);
		tv2 = NULL;
	}
	if(de1)
	{
		delete(de1);
		de1 = NULL;
	}
	if(de2)
	{
		delete(de2);
		de2 = NULL;
	}
}

bool BooleanStatement::EvaluateBooleanArgument(Dictionary * dictionary, BooleanStatement * bs1, TypedValue * tv1, char * de1)
{
	bool b1;
	
	if(bs1)
	{
		b1 = bs1->Evaluate(dictionary);
	}
	else if(tv1)
	{
		if(tv1->IsBoolean())
		{
			b1 = *((bool *)(tv1->GetValue()));
		}
		else
			b1 = false;
	}
	else if(de1)
	{
		TypedValue * tv = dictionary->GetTypedValue(de1);
		if(tv && tv->IsBoolean())
		{
			b1 = *((bool *)(tv->GetValue()));
		}
		else
			b1 = false;
	}
	else
	{
		b1 = false;
	}
	return b1;
}	
bool BooleanStatement::Evaluate(Dictionary * dictionary)
{
	//printf("BooleanStatement::Evaluate - operation = %s\n",operation);
	if(strcmp(operation, "AND") == 0)
	{
		bool b1 = EvaluateBooleanArgument(dictionary, bs1, tv1, de1);
		bool b2 = EvaluateBooleanArgument(dictionary, bs2, tv2, de2);
		
		return b1 && b2;
		
	}
	else if(strcmp(operation, "OR") == 0)
	{
		bool b1 = EvaluateBooleanArgument(dictionary, bs1, tv1, de1);
		
		if(b1)
			return b1;
			
		b1 = EvaluateBooleanArgument(dictionary, bs2, tv2, de2);
		
		return b1;
	}
	else if(strcmp(operation, "EQUAL") == 0)
	{
		if(tv1)
		{
			if(tv2)
			{
				return *tv1 == *tv2;	
			}
			else if(de2)
			{
				TypedValue * tv = dictionary->GetTypedValue(de2);
				return *tv1 == *tv;
			}
			else if(bs2)
			{
				if(strcmp(tv1->GetType(), BOOL_TYPE_STRING) == 0)
				{
					return bs2->Evaluate(dictionary) == *((bool *)tv1->GetValue());
				}
			}
		}
		else if(de1)
		{
			TypedValue * tvA = dictionary->GetTypedValue(de1);
			if(tv2)
			{
				return *tvA == *tv2;
			}
			else if(de2)
			{
				TypedValue * tvB = dictionary->GetTypedValue(de2);
				return *tvA == *tvB;
			}
			else if(bs2)
			{
				if(strcmp(tvA->GetType(), BOOL_TYPE_STRING) == 0)
				{
					return bs2->Evaluate(dictionary) == *((bool *)tvA->GetValue());
				}
			}
			return false;
		}
		else if(bs1)
		{
			if(tv2)
			{
				if(strcmp(tv2->GetType(), BOOL_TYPE_STRING) == 0)
				{
					return bs1->Evaluate(dictionary) == *((bool *)tv2->GetValue());
				}
			}
			else if(de2)
			{
				TypedValue * tvA = dictionary->GetTypedValue(de2);
				if(strcmp(tvA->GetType(), BOOL_TYPE_STRING) == 0)
				{
					return bs1->Evaluate(dictionary) == *((bool *)tvA->GetValue());
				}
			}
			else if(bs2)
			{
				return bs1->Evaluate(dictionary) == bs2->Evaluate(dictionary);
			}
			return false;
		}
	}
	return false;
}
